/*
* Copyright (c) 2017 . All Rights Reserved.
*/
package com.cgmnx.admin.service.aop;

import com.cgmnx.admin.common.bean.CurrentUserInfo;
import com.cgmnx.admin.common.bean.UserContext;
import com.cgmnx.admin.common.util.WebUtils;
import com.cgmnx.admin.dao.entity.rbac.OperationLogEntity;
import com.cgmnx.admin.service.rbac.OperationLogService;
import lombok.extern.slf4j.Slf4j;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.Around;
import org.aspectj.lang.annotation.Aspect;
import org.aspectj.lang.annotation.Pointcut;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;

/**
 * @author: created  Date: 17/1/9 Time: 上午11:40
 * @version: 1.0
 */
@Slf4j
@Aspect
@Component
public class LoggingHandler {

    //注入Service用于把日志保存数据库
    @Autowired
    private OperationLogService operationLogService;

    /**
     * 获取注解中对方法的描述信息 用于service层注解
     *
     * @param joinPoint 切点
     * @return 方法描述
     * @throws Exception
     */
    public static Loggable getServiceMethodDescription(ProceedingJoinPoint joinPoint)
            throws Exception {
        String targetName = joinPoint.getTarget().getClass().getName();
        String methodName = joinPoint.getSignature().getName();
        Object[] arguments = joinPoint.getArgs();
        Class targetClass = Class.forName(targetName);
        Method[] methods = targetClass.getMethods();
        Loggable loggable = null;
        for (Method method : methods) {
            if (method.getName().equals(methodName)) {
                Class[] clazzList = method.getParameterTypes();
                if (clazzList.length == arguments.length) {
                    loggable = method.getAnnotation(Loggable.class);
                    break;
                }
            }
        }
        return loggable;
    }

    //Service层切点
    @Pointcut("@annotation(Loggable)")
    public void serviceAspect() {
    }

    /**
     * @param joinPoint
     */
    @Around("serviceAspect()")
    public Object doAround(ProceedingJoinPoint joinPoint) throws Throwable {

        // 获取request对象
        HttpServletRequest request = ((ServletRequestAttributes) RequestContextHolder.getRequestAttributes()).getRequest();
        //获取请求ip
        String ip = WebUtils.getRealIP(request);

        //获取上下文
        CurrentUserInfo userInfo = UserContext.getUserInfo();

        //获取用户请求方法的参数并序列化为JSON格式字符串
        StringBuilder params = new StringBuilder();
        if (joinPoint.getArgs() != null && joinPoint.getArgs().length > 0) {
            for (int i = 0; i < joinPoint.getArgs().length; i++) {
                params.append(joinPoint.getArgs()[i]).append(";");
            }
        }

        Object proceed = joinPoint.proceed();

        try {
            saveLog(userInfo, ip, joinPoint);
        } catch (Exception ex) {
            log.error("操作日志错误:", ex);
        }
         /*==========记录本地异常日志==========*/
        log.info("操作日志:{}代码:{}信息:{}参数:{}", joinPoint.getTarget().getClass().getName() + joinPoint.getSignature().getName(), params);
        return proceed;
    }

    private void saveLog(CurrentUserInfo userInfo, String ip, ProceedingJoinPoint joinPoint) throws Exception {
        Loggable loggable = getServiceMethodDescription(joinPoint);
        OperationLogEntity logEntity = new OperationLogEntity();
        logEntity.setContent(loggable.description());
        logEntity.setOperationType(loggable.type());
        logEntity.setOperatorName(userInfo.getUserId());
        logEntity.setIp(ip);

        logEntity.setCreateUser(userInfo.getUserId());
        logEntity.setUpdateUser(userInfo.getUserId());

        operationLogService.save(logEntity);
    }


}